import { useMessage } from '@renderer/hooks/message'
import { useCommonTools } from '@renderer/hooks/commonTools'
const messageTip = useMessage()
const commonTools = useCommonTools()

export function useFilereader() {
    // 根据文件格式解析文件
    const parseUpgradeFile = (fileUrl: string, bytes) => {
        const fileType = commonTools.getFileExtensionFromUrl(fileUrl);

        let fileByteLists: number[] = [];
        switch (fileType) {
            case 'bin': fileByteLists = parseBin(bytes); break;
            case 'hex': fileByteLists = parseHex(bytes); break;
            case 'txt': fileByteLists = parseTxt(bytes); break;
            // case 'json': parseJson(); break;
        }

        return fileByteLists;
    }

    const parseBin = (fileBytess: any[]) => {
        console.log('fileBytes --- bin-- origin', fileBytess)
        const fileBytes = new Uint8Array(fileBytess)

        console.log('fileBytes --- bin', fileBytes)
        let address = 0;
        const fileByteLists: any[] = [];
        const maxFrameLen = 128;
        const packCount = fileBytes.length / maxFrameLen;
        const allCount = Math.ceil(packCount);

        for (let i = 0; i < allCount; i++) {
            let length = maxFrameLen;

            if (i === allCount - 1) {
                length = fileBytes.length - i * maxFrameLen;
            }

            const addressData = commonTools.toByteArray(address, false);
            const bytes: any = new Array(addressData.length + length).fill(0)
            arrayCopy(addressData, 0, bytes, 0, addressData.length)
            arrayCopy(fileBytes, maxFrameLen * i, bytes, addressData.length, length)

            fileByteLists.push(bytes);
            address += length;
        }

        console.log('fileByteLists --- bin', fileByteLists);
        return fileByteLists;
    }

    const parseBins = (fileBytes) => {
        const fileBytesArray = new Uint8Array(fileBytes)

        let address = 0;
        const fileByteLists: any[] = [];
        const maxFrameLen = 128;
        const totalBag = Math.ceil(fileBytesArray.length / maxFrameLen);

        for (let i = 0; i < totalBag; i++) {
            let length = maxFrameLen;

            if (i === totalBag - 1) {
                length = fileBytesArray.length - i * length;
            }


            const addressData = commonTools.toByteArray(address, false);
            const eachBagData = fileBytesArray.slice(address, address + length);
            fileByteLists.push([...addressData, ...eachBagData])
            address += length;
        }

        console.log('fileByteLists1', fileByteLists)
        return fileByteLists;
    }

    /**【类型】 04:基地址 ， 00:数据 ，05,01为结尾
     * 【:】  【数据长度】    【地址】  【类型】    【数据】    【校验】
     *   :         02           0000     04          0801        F1   
     * @param fileBytes 
     * @param maxFrameLen  最大数据长度
     * @returns 
     */
    const parseHex = (fileBytes: any[]) => {
        console.log('fileBytes', fileBytes)
        let dataList: any[] = [];

        try {
            // 数据
            let dataIndex = 0;
            let hexContent = bufferToUnit8Array(fileBytes)
            const lines = hexContent.split('\r\n');
            // 当前行字符串
            let hexLineStr = lines[dataIndex];
            // 基础地址
            let startAddress = new Array(2).fill(0)
            // 数据长度
            const lenPos = 0
            // 地址
            const addressPos = 1
            // 类型
            const typePos = 3
            // 数据
            const dataPos = 4
            // 整合最大数据帧长
            const maxFrameLen = 120
            let cmd: number[] = []
            // 起始地址
            let cmdAddress = 0

            while (hexLineStr) {
                if (!hexLineStr.startsWith(':', 0)) {
                    // throw new Error('数据不合规')
                    break;
                }

                if (hexLineStr.length > 11) {
                    // 数据
                    const cmdData = commonTools.hexStringToHexArray(hexLineStr.substring(1, hexLineStr.length))
                    // 类型
                    const type = cmdData[typePos]

                    //基地址
                    if (type === 0x04) {
                        startAddress[0] = cmdData[dataPos]
                        startAddress[1] = cmdData[dataPos + 1]

                        hexLineStr = lines[++dataIndex]
                        continue;
                    }

                    if (type === 0x01 || type === 0x05) {
                        hexLineStr = lines[++dataIndex]

                        continue
                    }

                    // 数据长度
                    const dataLen = cmdData[lenPos]

                    if ((cmd.length + dataLen) > maxFrameLen) {
                        cmdAddress += (cmd.length - 4)
                        dataList.push(cmd)
                        cmd = []
                    }

                    // 地址
                    const address = cmdData.slice(addressPos, addressPos + 2)

                    if (!cmd.length) {
                        //起始
                        cmd.push(...commonTools.toByteArray(cmdAddress, false))
                        cmd.push(...startAddress)
                        cmd.push(...address)
                    }

                    const data = cmdData.slice(dataPos, dataPos + dataLen)

                    cmd.push(...data)
                }
                hexLineStr = lines[++dataIndex]
            }

            dataList.push(cmd)
        } catch (error: any) {
            messageTip.error(`parse Hex error ${error?.message}`)
        }

        console.log('dataList --- hex', dataList)
        return dataList;
    }

    const parseTxt = (fileBytes: any[]) => {
        console.log('txt文件原数据', fileBytes)
        const dataList: any[] = [];

        try {
            // 数据
            let dataIndex = 0;
            let hexContent = bufferToUnit8Array(fileBytes)
            const lines = hexContent.split('\r\n')
            console.log('lines', lines);
            // 当前行字符串
            let hexLineStr: string = lines[dataIndex];
            // 数据最长128 字节
            const maxFrameLen = 128
            let cmdBuilder = ''
            let emptyLine = 0

            while (emptyLine < 5) {
                if (!hexLineStr) {
                    //连续空行，则认为后续没内容了
                    emptyLine++
                    hexLineStr = lines[++dataIndex]
                    continue
                }

                //重置空行
                emptyLine = 0

                if (hexLineStr.startsWith('//', 0)) {
                    //注释不处理
                    hexLineStr = lines[++dataIndex]
                    continue
                }

                const hexArr = hexLineStr.split(':')
                if (hexArr.length < 2) {
                    // 格式不正确
                    continue
                }

                const address = hexArr[0]
                const data = hexArr[1]
                if (cmdBuilder.length + data.length > maxFrameLen) {
                    dataList.push(commonTools.hexStringToHexArray(cmdBuilder.toString()))
                    cmdBuilder = ''
                }

                if (cmdBuilder === '') {
                    cmdBuilder += address
                }
                cmdBuilder += data
                hexLineStr = lines[++dataIndex]
            }

            dataList.push(commonTools.hexStringToHexArray(cmdBuilder.toString()))
        } catch (error: any) {
            messageTip.error(`parse txt error ${error?.message}`)
        }

        console.log('dataList --- txt', dataList)
        return dataList
    }

    // unimaster 自升级APP
    const parseUnimasterAppHex = (fileBytes) => {
        let dataList: any[] = [];

        try {
            // 数据
            let dataIndex = 0;
            let hexContent = bufferToUnit8Array(fileBytes)
            const lines = hexContent.split('\r\n');
            console.log('lines', lines);
            // 当前行字符串
            let hexLineStr = lines[dataIndex];
            // 基础地址
            let startAddress = new Array(2).fill(0)
            // 数据长度
            const lenPos = 0
            // 地址
            const addressPos = 1
            // 类型
            const typePos = 3
            // 数据
            const dataPos = 4
            // 整合最大数据帧长
            const maxFrameLen = 116
            let cmd: number[] = []

            while (hexLineStr) {
                if (!hexLineStr.startsWith(':', 0)) {
                    // throw new Error('数据不合规')
                    break;
                }

                if (hexLineStr.length > 11) {
                    // 数据
                    const cmdData = commonTools.hexStringToHexArray(hexLineStr.substring(1, hexLineStr.length))
                    // 类型
                    const type = cmdData[typePos]

                    //基地址
                    if (type === 0x04) {
                        startAddress[0] = cmdData[dataPos]
                        startAddress[1] = cmdData[dataPos + 1]

                        hexLineStr = lines[++dataIndex]
                        continue;
                    }

                    if (type === 0x01 || type === 0x05) {
                        hexLineStr = lines[++dataIndex]

                        continue
                    }

                    // 数据长度
                    const dataLen = cmdData[lenPos]

                    if ((cmd.length + dataLen) > maxFrameLen) {
                        dataList.push(cmd)
                        cmd = []
                    }

                    // 地址
                    const address = cmdData.slice(addressPos, addressPos + 2)

                    if (!cmd.length) {
                        //起始
                        cmd.push(...startAddress)
                        cmd.push(...address)
                    }

                    const data = cmdData.slice(dataPos, dataPos + dataLen)

                    cmd.push(...data)
                }
                hexLineStr = lines[++dataIndex]
            }

            dataList.push(cmd)
        } catch (error: any) {
            messageTip.error(`parse Hex error ${error?.message}`)
        }

        return dataList;
    }

    /**
     * 实时烧录  app 
     * @param fileUrl 类型
     * @param bytes 数据 arraybuffer
     * @returns bytesArr
     */
    const parseOnlineUpgradeFile = (fileUrl: string, bytes) => {
        const fileType = commonTools.getFileExtensionFromUrl(fileUrl);

        let fileByteLists: number[] = [];
        switch (fileType) {
            case 'bin': fileByteLists = parseOnlineBin(bytes); break;
            case 'hex': fileByteLists = parseUnimasterAppHex(bytes); break;
        }

        return fileByteLists;
    }

    /**
     * 解析在线烧录bin 文件
     * @param fileBytes 数据 arraybuffer
     * @returns 
     */
    const parseOnlineBin = (fileBytes) => {
        const fileBytesArray = new Uint8Array(fileBytes)

        let address = 0;
        const fileByteLists: any[] = [];
        const maxFrameLen = 116;
        const totalBag = Math.ceil(fileBytesArray.length / maxFrameLen);

        for (let i = 0; i < totalBag; i++) {
            let length = maxFrameLen;

            if (i === totalBag - 1) {
                length = fileBytesArray.length - i * length;
            }

            const eachBagData = fileBytesArray.slice(address, address + length);
            fileByteLists.push([...eachBagData])
            address += length;
        }

        console.log('fileByteLists -- online bin', fileByteLists)
        return fileByteLists;
    }

    const checkConfigEmpty = (jsonValue, name) => {
        return jsonValue[name] !== "" ? jsonValue[name] & 0xff : "";
    };

    const checkConfigSpecialEmpty = (jsonValue, name, value) => {
        return jsonValue[name] !== "" ? value : "";
    };

    const stringToHex = (str) => {
        var val = "";
        for (let i = 0; i < str.length; i++) {
            if (val == "") val = str.charCodeAt(i).toString(16);
            else val += "," + str.charCodeAt(i).toString(16);
        }
        return val;
    }

    const writeConfig = (jsonValue) => {
        let configBytes: any = []
        if (jsonValue) {
            configBytes[0] = checkConfigEmpty(jsonValue, "backlightBrightness"); // 【背光亮度】取值范围1~5，默认5
            configBytes[1] = checkConfigEmpty(jsonValue, "sleepTime"); // 【休眠时间】取值范围0~10，单位：min，默认10
            var date = new Date();
            configBytes[2] = date.getFullYear() - 2000; //系统时间年
            configBytes[3] = date.getMonth() + 1; //系统时间月
            configBytes[4] = date.getDate(); //系统时间日
            configBytes[5] = date.getHours(); //系统时间时
            configBytes[6] = date.getMinutes(); //系统时间分  //BC351还需要增加秒
            configBytes[7] = checkConfigEmpty(jsonValue, "voltage");    // 【系统电压】取值范围[24, 36, 48, 52, 60, 72]，单位：V，默认48
            configBytes[8] = checkConfigEmpty(jsonValue, "powerGear");  // 【助力档位数】取值范围 [3, 4, 5, 6, 7, 8, 9], 默认5
            configBytes[9] = checkConfigEmpty(jsonValue, "assist"); // 【助力正反】取值范围0/1， 0：助力正，1：助力反，默认0
            configBytes[10] = checkConfigEmpty(jsonValue, "assistStartMagnetNumber"); // 【助力开始磁钢数】取值范围2~64，默认2
            configBytes[11] = checkConfigEmpty(jsonValue, "assistPercentage"); // 【助力比例】取值范围0~255，通常6颗磁钢设为128， 12颗磁钢设为64。默认128
            configBytes[12] = checkConfigEmpty(jsonValue, "rotateHandle"); //【转把分档】取值范围0 /1， 0：不分，1：分，默认0
            configBytes[13] = checkConfigEmpty(jsonValue, "rotateHandleSpeedLimit"); // 【转把限速6kmph】取值范围0 /1， 0：正常转把，1：转把限速6Km，默认0
            configBytes[14] = checkConfigEmpty(jsonValue, "slowStart"); // 【缓启动参数】取值范围0~3， 0最强，3最缓，默认1
            configBytes[15] = checkConfigEmpty(jsonValue, "speedSteel"); // 【测速磁钢数】取值范围0~15，默认1
            configBytes[16] = checkConfigSpecialEmpty(jsonValue, "undervoltage", ((jsonValue.undervoltage * 1000) & 0xff00) >> 8); //高位 【欠压门限】取值范围0~65535，单位：mV，默认11500+20000=31500mV   为什么+30000，实际选择时，从30000开始选择，配置文件给的值是顺序值，不是实际值
            configBytes[17] = checkConfigSpecialEmpty(jsonValue, "undervoltage", (jsonValue.undervoltage * 1000) & 0x00ff); //低位 【欠压门限】取值范围0~65535，单位：mV，默认11500+20000=31500mV
            configBytes[18] = checkConfigEmpty(jsonValue, "currentlimiting"); // 【限流门限】取值范围0~255，单位：A，默认12
            configBytes[19] = checkConfigEmpty(jsonValue, "assistLimit"); // 【助力限速门限】取值范围10~41，单位：KM/H，默认25   为什么+10，是因为数值放到下拉列表中选择时，是从0开始的，配置文件给的值是顺序值，不是实际值
            configBytes[20] = checkConfigEmpty(jsonValue, "wheelDiameter"); // 【轮径代码】取值范围如下所示 ，默认5： ---字典  18: 9, 20: 10,22: 11,24: 12,28: 14,0: 16,1: 18, 2: 20,3: 22,4: 24,5: 26, 6: "700C",7: 28,58: 29,
            configBytes[21] = checkConfigEmpty(jsonValue, "batteryVoltageChangeTime"); // 【电量显示变化时间】取值范围1~60，单位：秒，默认30
            configBytes[22] = checkConfigEmpty(jsonValue, "allLineErrTimeOut"); // 【总线故障超时时间】取值范围5~255，单位：秒，默认10
            configBytes[23] = checkConfigEmpty(jsonValue, "smoothLevel"); // 【速度平滑等级】取值范围0~10，0为关闭平滑，1表示平滑为最快，10表示平滑为最慢，默认4
            configBytes[24] = checkConfigEmpty(jsonValue, "unit"); // 【显示单位】取值范围0~1，0：公制，1：英制
            configBytes[25] = checkConfigEmpty(jsonValue, "bluetooth"); // 【蓝牙】取值范围0~1，0：无蓝牙，1：有蓝牙
            configBytes[26] = checkConfigSpecialEmpty(jsonValue, "perimeter", (jsonValue.perimeter & 0xff00) >> 8); //高位 【周长】取值范围0~9999，单位：mm
            configBytes[27] = checkConfigSpecialEmpty(jsonValue, "perimeter", jsonValue.perimeter & 0x00ff); //低位 【周长】取值范围0~9999，单位：mm
            configBytes[28] = checkConfigEmpty(jsonValue, "agreement"); // 【协议】取值范围0~255；0：KM5S，1：锂电2号，2、八方，3、J协议
            configBytes[29] = checkConfigEmpty(jsonValue, "power"); // 【电量计算方式】取值范围0~2；0：控制器上报电压，仪表计算电量；1：控制器上报电量；2：仪表检查电压，仪表计算电量；
            configBytes[30] = checkConfigEmpty(jsonValue, "driveAssist"); // 【推车助力功能】取值范围0~1；0无推车助力功能，1为有推车助力功能
            configBytes[31] = checkConfigEmpty(jsonValue, "defaultGear"); // 【默认档位】取值范围0~9；
            configBytes[32] = checkConfigEmpty(jsonValue, "logo"); // 【LOGO项】取值范围0~9；0为迪太界面，1为中性界面，2为客户界面
            configBytes[33] = checkConfigEmpty(jsonValue, "serialLevel"); // 【串口通讯电平】取值范围0~1；0：3.3V，1：5V
            configBytes[34] = checkConfigEmpty(jsonValue, "buzzerSwitch"); // 【蜂鸣器开关】取值范围0~1；0：开，1：关
            configBytes[35] = checkConfigEmpty(jsonValue, "highSpeedBuzzerRemind"); // 【高速蜂鸣器提醒】取值范围0~99；
            configBytes[36] = checkConfigEmpty(jsonValue, "cruise"); // 【定速巡航功能】取值范围0~1；0：开，1：关
            configBytes[37] = checkConfigSpecialEmpty(jsonValue, "startupPasswd", (jsonValue.startupPasswd & 0xff00) >> 8); // 【开机密码】取值范围0~9999；
            configBytes[38] = checkConfigSpecialEmpty(jsonValue, "startupPasswd", jsonValue.startupPasswd & 0x00ff); // 【开机密码】取值范围0~9999；
            configBytes[39] = checkConfigSpecialEmpty(jsonValue, "highMenuPasswd", (jsonValue.highMenuPasswd & 0xff00) >> 8); // 【菜单密码】取值范围0~9999；
            configBytes[40] = checkConfigSpecialEmpty(jsonValue, "highMenuPasswd", jsonValue.highMenuPasswd & 0x00ff); // 【菜单密码】取值范围0~9999；
            configBytes[41] = checkConfigEmpty(jsonValue, "factoryReset"); // 【恢复出厂设置】取值范围0~1；0：YES，1：NO
            configBytes[42] = checkConfigEmpty(jsonValue, "ebikeName"); // 【车名】取值范围0~99；0：Pace500，1：Pace350，2：Level，3：Sinch，4：Aventure，5：Pace ,6:Sinch ST ,	7:Pace500 V2,8:	Pace350 V2,9:Soltera,10:Soltera-7S,11:Cruiser,12:Aventure Pro
            configBytes[43] = checkConfigSpecialEmpty(jsonValue, "motorSys", (jsonValue.motorSys & 0xff00) >> 8); // 【电机功率】取值范围 0-999；
            configBytes[44] = checkConfigSpecialEmpty(jsonValue, "motorSys", jsonValue.motorSys & 0x00ff); // 【电机功率】取值范围 0-999；
            configBytes[45] = checkConfigSpecialEmpty(jsonValue, "batteryCap", (jsonValue.batteryCap & 0xff00) >> 8); // 【电池容量】取值范围0~9999；
            configBytes[46] = checkConfigSpecialEmpty(jsonValue, "batteryCap", jsonValue.batteryCap & 0x00ff); // 【电池容量】取值范围0~9999；
            configBytes[47] = checkConfigSpecialEmpty(jsonValue, "showWheelsize", (jsonValue.showWheelsize & 0xff00) >> 8); // 【显示轮径】取值范围 0-999；
            configBytes[48] = checkConfigSpecialEmpty(jsonValue, "showWheelsize", jsonValue.showWheelsize & 0x00ff); // 【显示轮径】取值范围 0-999；
            configBytes[49] = checkConfigEmpty(jsonValue, "tiresSize"); // 【车轮宽度】取值范围0~99；
            configBytes[50] = checkConfigSpecialEmpty(jsonValue, "carModel", parseInt(stringToHex(jsonValue.carModel.substring(0, 1)), 16)); // 【车型】取值范围：两位字符；
            configBytes[51] = checkConfigSpecialEmpty(jsonValue, "carModel", parseInt(stringToHex(jsonValue.carModel.substring(1, 2)), 16)); // 【车型】取值范围：两位字符；
            configBytes[52] = checkConfigEmpty(jsonValue, "turnOnPasswd");
            configBytes[53] = checkConfigEmpty(jsonValue, "menuPassword");
        }

        return configBytes;
    }

    const arrayCopy = (src, srcPos, dest, destPos, length) => {
        if (srcPos < 0 || destPos < 0 || length < 0) {
            throw new Error("Index out of bounds exception");
        }
        if (srcPos + length > src.length || destPos + length > dest.length) {
            throw new Error("Index out of bounds exception");
        }

        for (let i = 0; i < length; i++) {
            dest[destPos + i] = src[srcPos + i];
        }
    }

    // 字节流转字符流
    const bufferToUnit8Array = (buffer) => {
        const decoder = new TextDecoder('utf-8');
        const hexContent = decoder.decode(buffer);

        return hexContent;
    }

    // json 文件解析
    const parseJson = (fileData): any => {
        return new Promise((resolve) => {
            try {
                if (typeof FileReader === 'undefined') {
                    messageTip.info('您的浏览器不支持文件读取。')
                    throw new Error('您的浏览器不支持文件读取。')
                }

                const reader = new FileReader()
                reader.readAsText(fileData)
                reader.onload = (e) => {
                    const content: any = e?.target?.result
                    const transContent = JSON.parse(content)
                    resolve(transContent)
                }
            } catch (error) {
                console.error(error)
            }
        })
    }

    const parseIni = (fileData): any => {
        return new Promise((resolve) => {
            try {
                if (typeof FileReader === 'undefined') {
                    messageTip.info('您的浏览器不支持文件读取。')
                    throw new Error('您的浏览器不支持文件读取。')
                }

                const reader = new FileReader()
                reader.readAsText(fileData)
                reader.onload = (e) => {
                    const content: any = e?.target?.result
                    const iniData = convertIniToJson(content)
                    resolve(iniData)
                }
            } catch (error) {
                console.error(error)
            }
        })
    }

    const convertIniToJson = (data) => {
        const regex = {
            section: /^\s*\s*([^]*)\s*\]\s*$/,

            param: /^\s*([\w\.\-\_]+)\s*=\s*(.*?)\s*$/,

            comment: /^\s*;.*$/,
        };

        const value: any = {};

        const lines = data.split(/\r\n|\r|\n/);

        let section = null;

        lines.forEach(function (line) {
            if (regex.comment.test(line)) {
                return;
            } else if (regex.param.test(line)) {
                var match = line.match(regex.param);
                if (section) {
                    value[section][match[1]] = match[2];
                } else {
                    value[match[1]] = match[2];
                }
            } else if (regex.section.test(line)) {
                // var match = line.match(regex.section);
                // value[match[1]] = {};
                // section = match[1];
            } else if (line.length == 0 && section) {
                section = null;
            }
        });

        return value;
    }

    const toArrayBuffer = (fileData) => {
        return new Promise((resolve, reject) => {
            try {
                if (typeof FileReader === 'undefined') {
                    messageTip.info('您的浏览器不支持文件读取。')
                    throw new Error('您的浏览器不支持文件读取。')
                }

                const reader = new FileReader()
                reader.onload = (e) => {
                    const arrayBuffer = e?.target?.result
                    resolve(arrayBuffer)
                }

                reader.onerror = (e) => {
                    console.error('文件读取出错：', e?.target?.error)
                }
                reader.readAsArrayBuffer(fileData)
            } catch (error: any) {
                reject(error.message)
            }
        })
    }

    // 获取文件名称
    const transFileName = (fileName: string, suffix: string) => {
        return fileName?.slice(0, fileName.lastIndexOf(`.${suffix}`))
    }

    // 3A 协议
    const cmd3aSum = (cmd, data) => {
        const CMD_HEAD = 0x3A
        const CMD_ADDRESS = 0x1A
        const CMD_END1 = 0x0D
        const CMD_END2 = 0x0A

        let cmdData = [] as number[];
        // 命令头
        cmdData.push(CMD_HEAD);
        // 设备地址
        cmdData.push(CMD_ADDRESS);
        // 命令字
        cmdData.push(cmd);
        // 数据长度
        cmdData.push(data.length & 0xFF);
        // 循环取值
        data.forEach(item => cmdData.push(item))
        //校验生成 !!!!从设备地址 - 校验码之前
        let d = 0;
        for (let i = 1; i < cmdData.length; i++) {
            d += cmdData[i]
        }

        cmdData.push(d & 0xff);
        cmdData.push((d >> 8) & 0xff);
        cmdData.push(CMD_END1);
        cmdData.push(CMD_END2);

        return cmdData;
    }

    return {
        parseJson,
        parseIni,
        transFileName,
        parseUpgradeFile,
        writeConfig,
        toArrayBuffer,
        parseUnimasterAppHex,
        parseOnlineUpgradeFile,
        cmd3aSum
    }
}